package com.my.geojson.test.simple.crud;

import com.my.geojson.store.PostgisDataStore;
import lombok.extern.slf4j.Slf4j;
import org.geotools.data.*;
import org.geotools.data.collection.ListFeatureCollection;
import org.geotools.data.simple.SimpleFeatureCollection;
import org.geotools.data.simple.SimpleFeatureIterator;
import org.geotools.data.simple.SimpleFeatureSource;
import org.geotools.data.simple.SimpleFeatureStore;
import org.geotools.feature.FeatureIterator;
import org.geotools.feature.simple.SimpleFeatureBuilder;
import org.geotools.feature.simple.SimpleFeatureTypeBuilder;
import org.geotools.filter.text.cql2.CQL;
import org.geotools.filter.text.cql2.CQLException;
import org.geotools.referencing.crs.DefaultGeographicCRS;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.GeometryFactory;
import org.locationtech.jts.geom.Point;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opengis.filter.Filter;
import org.opengis.filter.identity.FeatureId;
import org.opengis.geometry.Geometry;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

@Slf4j
public class Crud {
    private static String tableName = "test";

    private GeometryFactory geometryFactory = new GeometryFactory();
//    GeometryFactory geometryFactory = JTSFactoryFinder.getGeometryFactory(null);


    public static void main(String[] args) throws Exception {
        Crud crud = new Crud();
//        crud.insertPointByLonLat(108.21,38.34);
        //id不能查询--？？
        SimpleFeatureCollection featureCollection =
                crud.queryFeatures("name = '张三'");
        List<Object> attributes = new ArrayList<>();
        SimpleFeatureIterator iterator = featureCollection.features();
        while (iterator.hasNext()) {
            SimpleFeature feature = iterator.next();
            org.locationtech.jts.geom.Geometry geom =
                    (org.locationtech.jts.geom.Geometry)
                            feature.getDefaultGeometry();
//                Point centroid = geom.getCentroid();
            attributes = feature.getAttributes();
            log.info("geomStr : "+ geom);
            log.info("attr ： "+ attributes.toString());
        }
    }

    //创建矢量要素Feature
    //使用单一简单要素SimpleFeature给大家讲解，暂不解析复杂多点线面要素源码。以单点Point为例给大家解析，参考类Point，SimpleFeature，Geometry
    public SimpleFeature createSimplePointFeatureByLonLat(Double lon, Double lat) throws IOException {

        DataStore postgisDataStore = PostgisDataStore.getInstance();
        SimpleFeatureSource simpleFeatureSource = postgisDataStore.getFeatureSource(tableName);
        SimpleFeatureType type = simpleFeatureSource.getSchema();

        SimpleFeatureBuilder featureBuilder = new SimpleFeatureBuilder(type);
        Point point = geometryFactory.createPoint(new Coordinate(lon,lat));
        //属性值顺序与SimpleFeatureType对应
        List<Object> resultList = new ArrayList<>();
        resultList.add(point);
        resultList.add(5678);
        resultList.add("erftg");
        featureBuilder.addAll(resultList);
        //构建要素
        SimpleFeature feature = featureBuilder.buildFeature("poi1");

        return feature;
    };

    //新增矢量数据
    //空间表数据增删改涉及到数据库事务，切记事务的提交，也可设置事务自动提交。
    //参考类SimpleFeatureStore，SimpleFeatureCollection，Transaction。
    public void  insertPointByLonLat(Double lon, Double lat) throws IOException {
        DataStore postgisDataStore = PostgisDataStore.getInstance();
        SimpleFeatureSource simpleFeatureSource = postgisDataStore.getFeatureSource(tableName);
        SimpleFeatureType type = simpleFeatureSource.getSchema();

        SimpleFeature feature = createSimplePointFeatureByLonLat(lon,lat);
        List<SimpleFeature> features = new ArrayList<>();
        features.add(feature);

//        if(simpleFeatureSource instanceof SimpleFeatureStore){
            SimpleFeatureStore featureStore = (SimpleFeatureStore) simpleFeatureSource;
            SimpleFeatureCollection featureCollection =
                    new ListFeatureCollection(type,features);
            //创建事务
            Transaction session = new DefaultTransaction("Adding");
            featureStore.setTransaction(session);
            try {
                List<FeatureId> added = featureStore.addFeatures(featureCollection);
                System.out.println( "Added "+added );
                //提交事务
                session.commit();
            }
            catch (Throwable t){
                System.out.println( "Failed to add features: "+t );
                try {
                    //事务回归
                    session.rollback();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
//        }
    }

//    矢量数据查询
//    空间数据查询可以用CQL语法来封装查询条件，可封装普通where条件，
//    也可封装空间分析（Contains，Within，BBox）等条件。
//    参考类Query，CQL，SimpleFeatureCollection
    public SimpleFeatureCollection queryFeatures(String cql_filter) throws Exception {
        Filter filter = CQL.toFilter(cql_filter);
        Query query = new Query(tableName,filter);
        DataStore postgisDataStore = PostgisDataStore.getInstance();
        SimpleFeatureSource featureSource = postgisDataStore.getFeatureSource(tableName);

//        SimpleFeatureStore featureStore = (SimpleFeatureStore) featureSource;
//        SimpleFeatureCollection featureCollection = featureStore.getFeatures(query);
        SimpleFeatureCollection featureCollection = featureSource.getFeatures(query);
        return featureCollection;
    }

    //查询
    public static ArrayList<SimpleFeature> queryMethod(String filterStr,
                                                       String layerName) throws IOException {
        DataStore pgDatastore = PostgisDataStore.getInstance();
        //pgDatastore为上文连接数据库获取相当于AE中的workspace
        //SimpleFeatureSource相当于AE中的featureClass
        SimpleFeatureSource featureSource = pgDatastore.getFeatureSource(layerName);
        ArrayList<SimpleFeature> featureList = new ArrayList<SimpleFeature>();
        if(featureSource==null)
            return featureList;
        try {
            Filter filter = CQL.toFilter(filterStr); // filterStr形式 如  name='武汉大学' or code like 'tt123%'
            SimpleFeatureCollection result = featureSource.getFeatures(filter);

            FeatureIterator<SimpleFeature> itertor = result.features();
            while (itertor.hasNext()) {
                SimpleFeature feature = itertor.next();
                featureList.add(feature);
            }
            itertor.close();
            return featureList;
        } catch (CQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return null;
    }

    //添加要素
    //添加一个feature到图层中 在添加前要确定构造featureType
    public static SimpleFeatureType createFeatureType(String typeName, Class type) {
        SimpleFeatureTypeBuilder builder = new SimpleFeatureTypeBuilder();
        builder.setName(typeName);
        builder.setCRS(DefaultGeographicCRS.WGS84); // <- Coordinate reference
        // system
        builder.add("the_geom", type);  //这个为地理属性字段 postgis中为 the——geom

        builder.add("StandName", String.class); // 这是其他属性字段 自己定义的....
        // build the type
        final SimpleFeatureType TYPE = builder.buildFeatureType();

        return TYPE;
    }
    //修改要素
    // 修改feacode为XX的要素的名字为featureName 地理方位为geo  (feacode StandName为你的属性字段自定义)
    public static boolean modifyFeature(String layerName, Geometry geo, String featureName, String FeaCode) throws IOException {
        DataStore pgDatastore = PostgisDataStore.getInstance();
        FeatureSource featureSource= pgDatastore.getFeatureSource(layerName);
        if (featureSource instanceof SimpleFeatureStore) {
            SimpleFeatureStore featureStore = (SimpleFeatureStore) featureSource;
            Transaction transaction = new DefaultTransaction("create");
            featureStore.setTransaction(transaction);
            try {
                String filterStr="FeaCode= '"+FeaCode+"'";
                String[] names=new String[2];
                names[0]="StandName";
                names[1]="the_geom";
                Object[] values=new Object[2];
                values[0]=featureName;
                values[1]=geo;
                featureStore.modifyFeatures(names, values, CQL.toFilter(filterStr));

                transaction.commit();
                return true;
            } catch (Exception problem) {
                problem.printStackTrace();
                try {
                    transaction.rollback();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            } finally {
                try {
                    transaction.close();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        } else {
            System.out.println(layerName + " does not support read/write access");
        }
        return false;
    }
    //要素操作
    /*

    //获取feature的geometry
    Geometry geo=(Geometry) feature.getDefaultGeometry();
    //获取geometry中的坐标 这里用string的方式保存
    int geoUnm = geo.getNumGeometries();  // 一个geometry可能含有n个geometry
    for (int i = 0; i < geoUnm; i++) {
        Geometry singleGeo = geo.getGeometryN(i); //获取其中每一个geometry
        int pointCount = singleGeo.getNumPoints();
        Coordinate[] coords = singleGeo.getCoordinates();
        for (int j = 0; j < pointCount; j++) {
            if (j == pointCount - 1)
                sBuilder.append(coords[j].x + "," + coords[j].y);
            else {
                sBuilder.append(coords[j].x + "," + coords[j].y
                                        + ";");
            }
        }
        if (i != geoUnm - 1) {
            sBuilder.append("|");
        }
    }
    //获取feature中的属性
    feature.getAttribute(arg0);
    * */

//    //拓扑查询
//    public static Filter getGeoFilter(FilterFactory2 ff,                //构建拓扑查询的filter
//                                      String geometryAttributeName, Geometry refGeo,
//                                      SpatialReltionType.TopoRelTypeEnum relType) {   //这个SpatialReltionType是我自己定义的。。。
//
//        switch (relType) {
//            case intersect:
//                return ff.intersects(ff.property(geometryAttributeName), ff
//                        .literal(refGeo));
//            case contains:
//                return ff.contains(ff.property(geometryAttributeName), ff
//                        .literal(refGeo));
//            case within:
//                return ff.within(ff.property(geometryAttributeName), ff
//                        .literal(refGeo));
//            case cross:
//                return ff.crosses(ff.property(geometryAttributeName), ff
//                        .literal(refGeo));
//            case overlaps:
//                return ff.overlaps(ff.property(geometryAttributeName), ff
//                        .literal(refGeo));
//            case touches:
//                return ff.touches(ff.property(geometryAttributeName), ff
//                        .literal(refGeo));
//            case equals:
//                return ff.equals(ff.property(geometryAttributeName), ff
//                        .literal(refGeo));
//            case disjoint:
//                return ff.disjoint(ff.property(geometryAttributeName), ff
//                        .literal(refGeo));
//            default:
//                return null;
//        }
//    }
//    // 普通的拓扑查询
//    public static ArrayList<Geometry> topoQueryMethod(Geometry refGeo,
//                                                      String layerName,
//                                                      SpatialReltionType.TopoRelTypeEnum relType) {
//        ArrayList<SimpleFeature> featurelist=new ArrayList<SimpleFeature>();
//        FilterFactory2 ff = CommonFactoryFinder.getFilterFactory2(null);
//        SimpleFeatureSource featureSource=pgDatastore.getFeatureSource(layerName);
//
//        SimpleFeatureType schema = featureSource.getSchema();
//        String geometryAttributeName = schema.getGeometryDescriptor().getLocalName();
//        Filter filter1= getGeoFilter(ff,geometryAttributeName, refGeo, relType);    //上面的方法
//        SimpleFeatureCollection result=null;
//        try {
//            result = featureSource.getFeatures(filter1);
//        } catch (IOException e) {
//            // TODO Auto-generated catch block
//            e.printStackTrace();
//        }
//        if(result==null)
//            return null;
//        FeatureIterator<SimpleFeature> itertor = result.features();
//        while (itertor.hasNext()) {
//            SimpleFeature feature = itertor.next();
//            featurelist.add(feature);
//        }
//        //这个方法是将feature转为geometry 自己定义的
//        return SpatialUtil.ConverToGeoList(featurelist);
//    }
//    //联合属性的拓扑查询
//    public static ArrayList<Geometry> topoQueryMethod(Geometry refGeo,
//                                                      String queryName, String layerName,
//                                                      SpatialReltionType.TopoRelTypeEnum relType) {
//        FilterFactory2 ff = CommonFactoryFinder.getFilterFactory2(null);
//        ArrayList<SimpleFeature> featurelist=new ArrayList<SimpleFeature>();
//        SimpleFeatureSource featureSource=pgDatastore.getFeatureSource(layerName);
//
//        SimpleFeatureType schema = featureSource.getSchema();
//        String geometryAttributeName = schema.getGeometryDescriptor().getLocalName();
//        Filter filter1= SpatialUtil.getGeoFilter(ff,geometryAttributeName, refGeo, relType);
//        Filter filter2=null;
//        try {
//            filter2=CQL.toFilter("StandName = '"+queryName+"'");
//        } catch (CQLException e1) {
//            // TODO Auto-generated catch block
//            e1.printStackTrace();
//        }
//        List<Filter> match = new ArrayList<Filter>();
//        match.add(filter1);
//        match.add(filter2);
//        Filter filter = ff.and(match);
//
//        SimpleFeatureCollection result=null;
//        try {
//            result = featureSource.getFeatures(filter);
//        } catch (IOException e) {
//            // TODO Auto-generated catch block
//            e.printStackTrace();
//        }
//        if(result==null)
//            return null;
//        FeatureIterator<SimpleFeature> itertor = result.features();
//        while (itertor.hasNext()) {
//            SimpleFeature feature = itertor.next();
//            featurelist.add(feature);
//        }
//        return SpatialUtil.ConverToGeoList(featurelist);
//    }


    //添加到图层的图层名，添加的要素空间属性和要素的某属性名
//    public static boolean addFeature(String layerName,Geometry geo,String featureName) throws IOException {
//        String type=geo.getGeometryType();
//        Class TypeClass=null;
//        if(type.toLowerCase().equals("point")){
//            TypeClass=Point.class;
//        }else if(type.toLowerCase().equals("polygon")){
//            TypeClass=Polygon.class;
//        }else if(type.toLowerCase().equals("polyline")){
//            TypeClass= Polyline.class;
//        }else if(type.toLowerCase().equals("multipolygon")){
//            TypeClass=MultiPolygon.class;
//        }
//        SimpleFeatureType featureType=createFeatureType(layerName,TypeClass);
//        SimpleFeatureCollection collection = FeatureCollections.newCollection();
//
//        SimpleFeatureBuilder featureBuilder = new SimpleFeatureBuilder(featureType);
//        /* Longitude (= x coord) first ! */
//        GeometryFactory geometryFactory = JTSFactoryFinder.getGeometryFactory(null);
//
//        featureBuilder.add(geo);
//        featureBuilder.add(featureName);
//
//        SimpleFeature feature = featureBuilder.buildFeature(null);
//        collection.add(feature);
//
//        DataStore pgDatastore = PostgisDataStore.getInstance();
//        FeatureSource featureSource=pgDatastore.getFeatureSource(layerName);
//        if (featureSource instanceof SimpleFeatureStore) {
//            SimpleFeatureStore featureStore = (SimpleFeatureStore) featureSource;
//            Transaction transaction = new DefaultTransaction("create");
//            featureStore.setTransaction(transaction);
//            try {
//                featureStore.addFeatures(collection);
//                transaction.commit();
//                return true;
//
//            } catch (Exception problem) {
//                problem.printStackTrace();
//                try {
//                    transaction.rollback();
//                } catch (IOException e) {
//                    // TODO Auto-generated catch block
//                    e.printStackTrace();
//                }
//
//            } finally {
//                try {
//                    transaction.close();
//                } catch (IOException e) {
//                    // TODO Auto-generated catch block
//                    e.printStackTrace();
//                }
//            }
//        } else {
//            System.out.println(layerName + " does not support read/write access");
//        }
//        return false;
//    }

}
